package master

import (
	"context"
	"crontab/common"
	"encoding/json"
	"time"

	clientv3 "go.etcd.io/etcd/client/v3"
)

type jobMgr struct {
	cli *clientv3.Client
}

var G_jobMgr jobMgr

func InitJobMgr() {
	config := clientv3.Config{
		Endpoints:   G_config.EtcdEndpoints,
		DialTimeout: time.Duration(G_config.EtcdDialTimeout) * time.Millisecond,
	}
	cli, err := clientv3.New(config)
	common.DealError("ectd", err)
	timeoutCtx, cancel := context.WithTimeout(context.Background(), config.DialTimeout)
	defer cancel()
	_, err = cli.Status(timeoutCtx, config.Endpoints[0])
	common.DealError("etcd连接不上", err)
	G_jobMgr.cli = cli
}

func (jobMgr *jobMgr) SaveJob(job *common.Job) (*common.Job, error) {
	jobKey := common.JOB_SAVE_DIR + job.Name
	jobValue, err := json.Marshal(job)
	if err != nil {
		return nil, err
	}
	res, err := jobMgr.cli.Put(context.TODO(), jobKey, string(jobValue), clientv3.WithPrevKV())
	if err != nil {
		return nil, err
	}
	if res.PrevKv != nil {
		oldJob := &common.Job{}
		err = json.Unmarshal(res.PrevKv.Value, oldJob)
		if err == nil {
			return oldJob, nil
		}
	}
	return nil, nil
}

func (jobMgr *jobMgr) DelJob(name string) (*common.Job, error) {
	jobKey := common.JOB_SAVE_DIR + name
	res, err := jobMgr.cli.Delete(context.TODO(), jobKey, clientv3.WithPrevKV())
	if err != nil {
		return nil, err
	}
	if len(res.PrevKvs) != 0 {
		oldJob := &common.Job{}
		_ = json.Unmarshal(res.PrevKvs[0].Value, &oldJob)
		return oldJob, nil
	}
	return nil, nil
}

func (jobMgr *jobMgr) ListJob() ([]*common.Job, error) {
	jobList := make([]*common.Job, 0)
	res, err := jobMgr.cli.Get(context.TODO(), common.JOB_SAVE_DIR, clientv3.WithPrefix())
	if err != nil {
		return jobList, err
	}
	for _, kvPair := range res.Kvs {
		// job := &common.Job{}
		// err = json.Unmarshal(kvPair.Value, job)
		job, err := common.UnpackJob(kvPair.Value)
		if err != nil {
			continue
		}
		jobList = append(jobList, job)
	}
	return jobList, nil
}

func (jobMgr *jobMgr) KillJob(name string) error {
	jobKey := common.JOB_KILL_DIR + name
	// 创建一个1秒的租约
	res, err := jobMgr.cli.Lease.Grant(context.TODO(), 1)
	if err != nil {
		return err
	}
	_, err = jobMgr.cli.Put(context.TODO(), jobKey, "", clientv3.WithLease(res.ID))
	if err != nil {
		return err
	}
	return nil
}
